package com.tencent.wxcloudrun.manager;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Resource;

import io.github.admin4j.http.util.HttpUtil;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencent.wxcloudrun.domain.TOrder;
import com.tencent.wxcloudrun.domain.TUser;
import com.tencent.wxcloudrun.dto.wx.*;
import com.tencent.wxcloudrun.exception.BusinessException;
import com.tencent.wxcloudrun.service.TOrderService;
import com.tencent.wxcloudrun.util.DateUtils;
import com.tencent.wxcloudrun.util.OkHttpUtil;
import com.tencent.wxcloudrun.util.RedisBusiUtil;
import com.tencent.wxcloudrun.vo.request.wx.*;
import com.tencent.wxcloudrun.vo.response.wx.*;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author ZhaoZiYin
 * @Date 2025/5/14
 * @Description 微信接口管理端
 */
@Service
@Slf4j
public class WxManager {

    @Value("${klee.appId}")
    private String appId;

    @Value("${klee.appEnvId}")
    private String appEnvId;

    @Value("${klee.appMchId}")
    private String appMchId;

    @Value("${klee.appSecret}")
    private String appSecret;

    @Value("${klee.actiBegnTemplateId}")
    private String actiBegnTemplateId;

    @Value("${klee.miniprogramState:formal}")
    private String miniprogramState;

    @Value("${klee.actiChosenTemplateId}")
    private String actiChosenTemplateId;

    @Value("${klee.actiStatUpdTemplateId}")
    private String actiStatUpdTemplateId;

    @Resource
    private TOrderService orderService;

    public WxGetPhoneNumberResponse getPhoneNumber(WxGetPhoneNumberRequest request) {
        log.info("获取用户手机号：入参=[{}]", request);
        WxGetPhoneNumberResponse response = new WxGetPhoneNumberResponse();
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
        try {
            log.info("获取用户手机号-调用微信http接口开始");
            JSONObject jsonObject = OkHttpUtil.post(url, JSON.toJSONString(request));
            if (jsonObject != null) {
                log.info("获取用户手机号-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                WxGetPhoneNumberDTO wxGetPhoneNumberDTO =
                    JSONObject.parseObject(jsonObject.toJSONString(), WxGetPhoneNumberDTO.class);
                response.setPhoneNumber(wxGetPhoneNumberDTO.getPhone_info().getPhoneNumber());
                log.info("获取用户手机号-调用微信http接口结束-出参=[{}]", wxGetPhoneNumberDTO);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("获取用户手机号：出参=[{}]", response);
        return response;
    }

    public WxLoginResponse login(WxLoginRequest request) {
        log.info("微信登录-服务处理开始-入参=[{}]", request);
        WxLoginResponse response;
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecret
            + "&js_code=" + request.getCode() + "&grant_type=authorization_code";
        try {
            log.info("微信登录-调用微信http接口开始");
            JSONObject jsonObject = OkHttpUtil.get(url, null);
            log.info("微信登录-调用微信http接口结束");
            response = JSONObject.parseObject(jsonObject.toJSONString(), WxLoginResponse.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("微信登录-服务处理完成-出参=[{}]", response);
        return response;
    }

    public Object qryRid(WxQryRidRequest request) {
        log.info("微信查询Rid-服务处理完成-出参=[{}]", request);
        JSONObject jsonObject;
        String url = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get";
        try {
            log.info("微信查询Rid-调用微信http接口开始");
            jsonObject = OkHttpUtil.post(url, JSON.toJSONString(request));
            log.info("微信查询Rid-调用微信http接口结束");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("微信查询Rid-服务处理完成-出参=[{}]", jsonObject);
        return jsonObject;
    }

    public void sendActiBegnSubsMsg(WxSendActiBegnSubsMsgRequest request) {
        log.info("推送活动开始订阅消息-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
        WxSendActiSubsMsgReqDTO reqDTO = new WxSendActiSubsMsgReqDTO();
        reqDTO.setTemplate_id(actiBegnTemplateId);
        reqDTO.setPage("/pages/acti/actidetl/actidetl?actiId=" + request.getActiId());
        reqDTO.setTouser(request.getWxOpenId());
        reqDTO.setData(getActiBegnSubsData(request));
        reqDTO.setMiniprogram_state(miniprogramState);
        log.info("推送活动开始订阅消息-调用微信http接口");
        try {
            JSONObject jsonObject = OkHttpUtil.post(url, JSON.toJSONString(reqDTO));
            WxSendActiSubsMsgResDTO resDTO =
                JSONObject.parseObject(jsonObject.toJSONString(), WxSendActiSubsMsgResDTO.class);
            if (Objects.equals(resDTO.getErrcode(), "0")) {
                log.info("推送活动开始订阅消息-推送成功");
            } else {
                log.info("推送活动开始订阅消息-推送失败，失败原因=[{}]", resDTO);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("推送活动开始订阅消息-服务处理完成");
    }

    public void sendActiChosenSubsMsg(WxSendActiChosenSubsMsgRequest request) {
        log.info("推送活动中选订阅消息-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
        WxSendActiSubsMsgReqDTO reqDTO = new WxSendActiSubsMsgReqDTO();
        reqDTO.setTemplate_id(actiChosenTemplateId);
        reqDTO.setPage(request.getPage());
        reqDTO.setTouser(request.getWxOpenId());
        reqDTO.setData(getActiChosenSubsData(request));
        reqDTO.setMiniprogram_state(miniprogramState);
        log.info("推送活动中选订阅消息-调用微信http接口");
        try {
            JSONObject jsonObject = OkHttpUtil.post(url, JSON.toJSONString(reqDTO));
            WxSendActiSubsMsgResDTO resDTO =
                JSONObject.parseObject(jsonObject.toJSONString(), WxSendActiSubsMsgResDTO.class);
            if (Objects.equals(resDTO.getErrcode(), "0")) {
                log.info("推送活动中选订阅消息-推送成功");
            } else {
                log.info("推送活动中选订阅消息-推送失败，失败原因=[{}]", resDTO);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("推送活动中选订阅消息-服务处理完成");
    }

    public void sendActiStatUpdSubsMsg(WxSendActiStatUpdSubsMsgRequest request) {
        log.info("推送活动状态更新订阅消息-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
        WxSendActiSubsMsgReqDTO reqDTO = new WxSendActiSubsMsgReqDTO();
        reqDTO.setTemplate_id(actiStatUpdTemplateId);
        reqDTO.setPage("/pages/acti/actijoin/actijoin?actiId=" + request.getActiId());
        reqDTO.setTouser(request.getWxOpenId());
        reqDTO.setData(getActiStatUpdSubsData(request));
        reqDTO.setMiniprogram_state(miniprogramState);
        log.info("推送活动状态更新订阅消息-调用微信http接口");
        try {
            JSONObject jsonObject = OkHttpUtil.post(url, JSON.toJSONString(reqDTO));
            WxSendActiSubsMsgResDTO resDTO =
                JSONObject.parseObject(jsonObject.toJSONString(), WxSendActiSubsMsgResDTO.class);
            if (Objects.equals(resDTO.getErrcode(), "0")) {
                log.info("推送活动状态更新订阅消息-推送成功");
            } else {
                log.info("推送活动状态更新订阅消息-推送失败，失败原因=[{}]", resDTO);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("推送活动状态更新订阅消息-服务处理完成");
    }

    @Transactional
    public WxPayResponse wxPay(WxPayRequest request) {
        WxPayResponse resDTO = new WxPayResponse();
        log.info("微信支付-服务处理开始-入参=[{}]", request);
        String url = "http://api.weixin.qq.com/_/pay/unifiedorder";
        WxPayDTO reqDTO = new WxPayDTO();
        reqDTO.setCallbackType(2);
        reqDTO.setEnvId(appEnvId);
        reqDTO.setFunctionName("");
        reqDTO.setContainer(request.getContainer());
        reqDTO.setSubMchId(appMchId);
        String currTime = DateUtils.nowStringDate() + DateUtils.nowStringTime();
        String randomStr = String.valueOf((int)Math.floor(Math.random() * 1000000000));
        String orderNo = currTime + randomStr;
        reqDTO.setNonceStr(orderNo);
        reqDTO.setBody(request.getBody());
        reqDTO.setAttach(request.getAttach());
        reqDTO.setOutTradeNo(orderNo);
        reqDTO.setTotalFee(request.getTotalFee());
        reqDTO.setSpbillCreateIp(request.getSpbillCreateIp());
        reqDTO.setTradeType("JSAPI");
        if (request.getUserId() != null) {
            TUser user = RedisBusiUtil.getUserInfo(request.getUserId());
            if (user != null) {
                reqDTO.setOpenid(user.getWxOpenId());
                reqDTO.setSubOpenid(user.getWxOpenId());
            }
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(reqDTO);
            log.info("微信支付-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("微信支付-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = mapper.readerFor(WxPayResponse.class).readValue(jsonObject.toJSONString());
                if (resDTO != null && resDTO.getErrcode() == 0) {
                    log.info("微信支付成功");
                } else {
                    log.info("微信支付失败，失败原因=[{}]", resDTO);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("微信支付-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    public WxQryOrderResponse wxQryOrder(WxQryOrderRequest request) {
        WxQryOrderResponse resDTO = new WxQryOrderResponse();
        log.info("查询微信订单信息-服务处理开始-入参=[{}]", request);
        String url = "http://api.weixin.qq.com/_/pay/queryorder";
        WxQryOrderReqDTO reqDTO = new WxQryOrderReqDTO();
        TOrder order = orderService.getById(request.getOrderId());
        if (Objects.isNull(order)) {
            throw new BusinessException("订单不存在");
        }
        reqDTO.setOutTradeNo(order.getStoreOrderNo());
        reqDTO.setSubMchId(appMchId);
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(reqDTO);
            log.info("查询微信订单信息-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("查询微信订单信息-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = JSONObject.parseObject(jsonObject.toJSONString(), WxQryOrderResponse.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("查询微信订单信息-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    public WxTraceWaybillResponse wxTraceWaybill(WxTraceWaybillRequest request) {
        WxTraceWaybillResponse resDTO = new WxTraceWaybillResponse();
        log.info("查询微信订单物流信息-服务处理开始-入参=[{}]", request);
        String url = "http://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/trace_waybill";
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(request);
            log.info("查询微信订单物流信息-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("查询微信订单物流信息-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = JSONObject.parseObject(jsonObject.toJSONString(), WxTraceWaybillResponse.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("查询微信订单物流信息-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    public WxDownloadfileResponse wxDownloadfile(WxDownloadfileRequest request) {
        WxDownloadfileResponse resDTO = new WxDownloadfileResponse();
        log.info("微信获取文件下载链接-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/tcb/batchdownloadfile";
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(request);
            log.info("微信获取文件下载链接-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("微信获取文件下载链接-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = JSONObject.parseObject(jsonObject.toJSONString(), WxDownloadfileResponse.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("微信获取文件下载链接-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    public WxUploadfileResponse wxUploadfile(WxUploadfileRequest request, File file) {
        WxUploadfileResponse resDTO = new WxUploadfileResponse();
        log.info("微信获取文件上传文件链接-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/tcb/uploadfile";
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(request);
            log.info("微信获取文件上传文件链接-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("微信获取文件上传文件链接-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = JSONObject.parseObject(jsonObject.toJSONString(), WxUploadfileResponse.class);
                wxUploadFileToServer(resDTO, request, file);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("微信获取文件上传文件链接-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    private void wxUploadFileToServer(WxUploadfileResponse resDTO, WxUploadfileRequest request, File file) {
        log.info("微信获取文件上传文件-服务处理开始-入参=[{}]", resDTO);
        String url = resDTO.getUrl();
        Map<String, Object> formParams = new HashMap<>();
        formParams.put("key", request.getPath());
        formParams.put("Signature", resDTO.getAuthorization());
        formParams.put("x-cos-security-token", resDTO.getToken());
        formParams.put("x-cos-meta-fileid", resDTO.getCosFileId());
        formParams.put("file", file);
        log.info("微信获取文件上传文件-调用微信http接口-参数=[{}]", formParams);
        Response response = HttpUtil.upload(url, formParams);
        if (!response.isSuccessful()) {
            throw new BusinessException(response.message());
        }
        log.info("微信获取文件上传文件-调用微信http接口-返回值=[{}]", response);
        log.info("微信获取文件上传文件-服务处理完成-出参=[{}]", response);
    }

    public WxMsgSecCheckResponse wxMsgSecCheck(WxMsgSecCheckRequest request) {
        WxMsgSecCheckResponse resDTO = new WxMsgSecCheckResponse();
        log.info("文本内容安全识别-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/wxa/msg_sec_check";
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(request);
            log.info("文本内容安全识别-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("文本内容安全识别-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = JSONObject.parseObject(jsonObject.toJSONString(), WxMsgSecCheckResponse.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("文本内容安全识别-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    public WxMediaCheckAsyncResponse wxMediaCheckAsync(WxMediaCheckAsyncRequest request) {
        WxMediaCheckAsyncResponse resDTO = new WxMediaCheckAsyncResponse();
        log.info("音视频内容安全识别-服务处理开始-入参=[{}]", request);
        String url = "https://api.weixin.qq.com/wxa/media_check_async";
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(request);
            log.info("音视频内容安全识别-调用微信http接口-参数=[{}]", json);
            JSONObject jsonObject = OkHttpUtil.post(url, json);
            if (jsonObject != null) {
                log.info("音视频内容安全识别-调用微信http接口-返回值=[{}]", jsonObject.toJSONString());
                resDTO = JSONObject.parseObject(jsonObject.toJSONString(), WxMediaCheckAsyncResponse.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("音视频内容安全识别-服务处理完成-出参=[{}]", resDTO);
        return resDTO;
    }

    /**
     * method description: 组装活动开始订阅消息内容
     *
     * @param request 请求入参
     * @return java.lang.String
     * @author Ryan Zhao
     * @date 2023-08-29 17:07
     */
    private WxActiBegnSubsMsgDataDTO getActiBegnSubsData(WxSendActiBegnSubsMsgRequest request) {
        WxActiBegnSubsMsgDataDTO wxActiBegnSubsMsgDataDTO = new WxActiBegnSubsMsgDataDTO();
        wxActiBegnSubsMsgDataDTO.setCharacter_string10(new WxSubsMsgValueDTO(request.getActiBegnTime()));
        wxActiBegnSubsMsgDataDTO.setThing6(new WxSubsMsgValueDTO(request.getActiName()));
        wxActiBegnSubsMsgDataDTO.setThing7(new WxSubsMsgValueDTO(request.getStoreName()));
        wxActiBegnSubsMsgDataDTO.setNumber5(new WxSubsMsgValueDTO(String.valueOf(request.getActiPrdVol())));
        log.info("推送活动开始订阅消息-组装消息推送内容=[{}]", com.alibaba.fastjson.JSONObject.toJSONString(wxActiBegnSubsMsgDataDTO));
        return wxActiBegnSubsMsgDataDTO;
    }

    /**
     * method description: 组装活动中选订阅消息内容
     *
     * @param request 请求入参
     * @return java.lang.String
     * @author Ryan Zhao
     * @date 2023-08-29 17:07
     */
    private WxActiChosenSubsMsgDataDTO getActiChosenSubsData(WxSendActiChosenSubsMsgRequest request) {
        WxActiChosenSubsMsgDataDTO wxActiChosenSubsMsgDataDTO = new WxActiChosenSubsMsgDataDTO();
        wxActiChosenSubsMsgDataDTO.setShort_thing3(new WxSubsMsgValueDTO(request.getChooseResult()));
        wxActiChosenSubsMsgDataDTO.setThing1(new WxSubsMsgValueDTO(request.getActiTitle()));
        wxActiChosenSubsMsgDataDTO.setShort_thing2(new WxSubsMsgValueDTO(request.getActiTypeName()));
        wxActiChosenSubsMsgDataDTO.setThing4(new WxSubsMsgValueDTO(request.getTips()));
        log.info("推送活动中选订阅消息-组装消息推送内容=[{}]", com.alibaba.fastjson.JSONObject.toJSONString(wxActiChosenSubsMsgDataDTO));
        return wxActiChosenSubsMsgDataDTO;
    }

    /**
     * method description: 组装活动中选订阅消息内容
     *
     * @param request 请求入参
     * @return java.lang.String
     * @author Ryan Zhao
     * @date 2023-08-29 17:07
     */
    private WxActiStatUpdSubsMsgDataDTO getActiStatUpdSubsData(WxSendActiStatUpdSubsMsgRequest request) {
        WxActiStatUpdSubsMsgDataDTO wxActiStatUpdSubsMsgDataDTO = new WxActiStatUpdSubsMsgDataDTO();
        wxActiStatUpdSubsMsgDataDTO.setThing1(new WxSubsMsgValueDTO(request.getActiName()));
        wxActiStatUpdSubsMsgDataDTO.setShort_thing3(new WxSubsMsgValueDTO(request.getActiStatName()));
        wxActiStatUpdSubsMsgDataDTO.setThing4(new WxSubsMsgValueDTO(request.getTips()));
        log.info("推送活动状态更新订阅消息-组装消息推送内容=[{}]",
            com.alibaba.fastjson.JSONObject.toJSONString(wxActiStatUpdSubsMsgDataDTO));
        return wxActiStatUpdSubsMsgDataDTO;
    }

}
